from flask import Flask, render_template, request, redirect, url_for, flash
import os
import pandas as pd
import plotly.express as px
import plotly.io as pio
from wordcloud import WordCloud
from PIL import Image
import matplotlib.pyplot as plt
from io import BytesIO
import base64

app = Flask(__name__, template_folder='templates')
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['SECRET_KEY'] = 'your-secret-key-here'

os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)


@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        flash('No file part')
        return redirect(url_for('index'))

    file = request.files['file']
    if file.filename == '':
        flash('No selected file')
        return redirect(url_for('index'))

    allowed_extensions = {'csv', 'xlsx', 'xls'}
    if '.' not in file.filename or \
            file.filename.rsplit('.', 1)[1].lower() not in allowed_extensions:
        flash('Invalid file type. Allowed: .csv, .xlsx, .xls')
        return redirect(url_for('index'))

    filename = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
    file.save(filename)

    try:
        if file.filename.endswith('.csv'):
            df = pd.read_csv(filename)
        elif file.filename.endswith(('.xlsx', '.xls')):
            df = pd.read_excel(filename)

        df = clean_and_preprocess_data(df)
        movie_avg_star = df.groupby(['Movie_Name_EN', 'Movie_Name_CN'])['Star'].mean().round(2).reset_index()
        top_20_movies = movie_avg_star.nlargest(20, 'Star')
        top_20_movies['Movie_Name'] = top_20_movies['Movie_Name_CN'] + '<br>(' + top_20_movies['Movie_Name_EN'] + ')'

        fig = px.bar(
            top_20_movies,
            x='Movie_Name',
            y='Star',
            title='平均星级最高的20部电影',
            labels={'Star': '平均星级', 'Movie_Name': '电影名称'},
            color='Star',
            color_continuous_scale='Viridis',
            text_auto=True
        )

        fig.update_layout(
            height=600,
            width=1000,
            xaxis_title='',
            yaxis_title='平均星级',
            yaxis_range=[0, 5],
            font=dict(family='SimHei, Arial'),
            title=dict(
                text='平均星级最高的20部电影',
                font=dict(size=20),
                x=0.5,
                xanchor='center'
            ),
            coloraxis_colorbar=dict(
                title='平均星级'
            )
        )

        fig.update_xaxes(tickangle=45, tickfont=dict(size=10))
        plot_html = pio.to_html(fig, full_html=False)

        movie_boxplot_data = df[['Movie_Name_CN', 'Movie_Name_EN', 'Star']].dropna()
        movie_boxplot_data['Movie_Name'] = movie_boxplot_data['Movie_Name_CN'] + '<br>(' + movie_boxplot_data[
            'Movie_Name_EN'] + ')'

        box_fig = px.box(
            movie_boxplot_data,
            x='Movie_Name',
            y='Star',
            title='电影评分箱线图',
            labels={'Star': '评分', 'Movie_Name': '电影名称'},
            notched=True,
            category_orders={'Movie_Name': sorted(movie_boxplot_data['Movie_Name'].unique())}
        )
        box_fig.update_layout(
            height=800,
            width=1200,
            xaxis_title='',
            yaxis_title='评分',
            yaxis_range=[0, 5],
            font=dict(family='SimHei, Arial'),
            title=dict(text='电影评分箱线图', font=dict(size=20), x=0.5, xanchor='center')
        )
        box_fig.update_xaxes(tickangle=45, tickfont=dict(size=10))
        box_html = pio.to_html(box_fig, full_html=False)

        # 获取所有电影名称
        movie_names = df[['Movie_Name_EN', 'Movie_Name_CN']].drop_duplicates()
        movie_names['Full_Name'] = movie_names['Movie_Name_CN'] + ' (' + movie_names['Movie_Name_EN'] + ')'

        with open('machine_learn/lda结果/低分评论_lda.html', 'r', encoding='utf-8') as f:
            low_lda_html = f.read()

        with open('machine_learn/lda结果/高分评论_lda(0).html', 'r', encoding='utf-8') as f:
            high_lda_html = f.read()

        return render_template('visualize.html',
                               filename=file.filename,
                               plot_html=plot_html,
                               box_html=box_html,
                               movie_names=movie_names['Full_Name'].tolist(),
                               low_lda_html=low_lda_html,
                               high_lda_html=high_lda_html
        )

    except Exception as e:
        flash(f'Error: {str(e)}')
        return redirect(url_for('index'))




@app.route('/generate_wordcloud', methods=['POST'])
def generate_wordcloud():
    movie_name = request.form.get('movie_name')
    movie_name_cn = movie_name.split(' (')[0]
    movie_name_en = movie_name.split(' (')[1][:-1]

    file_path = os.path.join(app.config['UPLOAD_FOLDER'], os.listdir(app.config['UPLOAD_FOLDER'])[0])
    if file_path.endswith('.csv'):
        df = pd.read_csv(file_path)
    elif file_path.endswith(('.xlsx', '.xls')):
        df = pd.read_excel(file_path)

    movie_comments = df[(df['Movie_Name_CN'] == movie_name_cn) & (df['Movie_Name_EN'] == movie_name_en)][
        'Comment'].str.cat(sep=' ')

    # 生成更大尺寸的词云图
    wordcloud = WordCloud(
        font_path='simhei.ttf',
        background_color='white',
        width=1200,
        height=800,
        max_font_size=100,
        min_font_size=10,
        collocations=False
    ).generate(movie_comments)

    img = BytesIO()
    wordcloud.to_image().save(img, format='PNG')
    img.seek(0)
    wordcloud_base64 = base64.b64encode(img.getvalue()).decode()

    return wordcloud_base64

    img = BytesIO()
    wordcloud.to_image().save(img, format='PNG')
    img.seek(0)
    wordcloud_base64 = base64.b64encode(img.getvalue()).decode()

    return wordcloud_base64


def clean_and_preprocess_data(df):
    required_columns = ['Username', 'Date', 'Star', 'Comment', 'Like']
    missing_columns = [col for col in required_columns if col not in df.columns]
    if missing_columns:
        raise ValueError(f"文件缺少必要的列: {', '.join(missing_columns)}")

    df_clean = df.copy()

    print(f"原始数据行数: {len(df_clean)}")
    df_clean.dropna(subset=required_columns, inplace=True)
    print(f"删除缺失值后行数: {len(df_clean)}")

    df_clean['Star'] = pd.to_numeric(df_clean['Star'], errors='coerce')
    df_clean.dropna(subset=['Star'], inplace=True)
    print(f"转换数据类型后行数: {len(df_clean)}")

    valid_ratings = (df_clean['Star'] >= 0) & (df_clean['Star'] <= 5)
    df_clean = df_clean[valid_ratings]
    print(f"过滤异常值后行数: {len(df_clean)}")

    text_columns = ['Username', 'Comment']
    for col in text_columns:
        df_clean[col] = df_clean[col].str.strip()

    try:
        df_clean['Date'] = pd.to_datetime(df_clean['Date'], errors='coerce')
        df_clean.dropna(subset=['Date'], inplace=True)
    except:
        pass

    if len(df_clean) == 0:
        raise ValueError("清理后的数据为空，请检查上传的文件内容")

    return df_clean


@app.route('/clustering_visualization')
def clustering_visualization():
    # 读取聚类质量报告文本
    with open('数据聚类+五个可视化图‘/cluster_quality_report.txt', 'r', encoding='utf-8') as f:
        quality_report = f.read()

    # 读取聚类结果图片并转为Base64（适用于clustering_results.png和optimal_clusters.png）
    def image_to_base64(filename):
        with open(filename, 'rb') as img_file:
            return base64.b64encode(img_file.read()).decode('utf-8')

    clustering_img = image_to_base64('数据聚类+五个可视化图‘/clustering_results.png')
    optimal_clusters_img = image_to_base64('数据聚类+五个可视化图‘/optimal_clusters.png')

    return render_template(
        'clustering.html',  # 新建前端模板
        quality_report=quality_report,
        clustering_img=clustering_img,
        optimal_clusters_img=optimal_clusters_img
    )
@app.route('/wordcloud_visualization')
def wordcloud_visualization():
    # 定义静态图片路径（需与实际存放路径一致）
    low_img_path = 'static/images/低分电影观众讨论高频词(2).png'
    high_img_path = 'static/images/高分电影观众讨论高频词(2).png'

    # 检查图片是否存在
    if not (os.path.exists(low_img_path) and os.path.exists(high_img_path)):
        flash('词云图文件未找到，请确认图片路径正确')
        return redirect(url_for('index'))

    # 生成图片的URL路径
    low_wordcloud_path = url_for('static', filename='images/低分电影观众讨论高频词(2).png')
    high_wordcloud_path = url_for('static', filename='images/高分电影观众讨论高频词(2).png')

    return render_template(
        'high_low_wordcloud.html',
        low_wordcloud_path=low_wordcloud_path,
        high_wordcloud_path=high_wordcloud_path
    )
if __name__ == '__main__':
    app.run(debug=True)